﻿using System.Collections.Generic;
using UnityEngine;

namespace NpcFramework.Traffic
{

    public enum TrafficPointStatus
    {
        Walkable = 1,
        NotWalkable = 2,
    }

    public class TrafficWaitPointData
    {
        public int index = 0;
        // 是否空余
        public bool status = true;
        public int npcId = -1;
        public Vector3 position;
        public Vector3 forward;
    }

    public class TrafficWayPointData
    {
        // 行人是否可以行走
        public TrafficPointStatus TrafficPointStatus;
        public List<TrafficWaitPointData> WaitPointData;
        public int CurrentWaitCount = 0;
    }

    public class TrafficManager : MonoBehaviour
    {
        
        // 红绿灯Map
        private Dictionary<int,TrafficLight> TrafficLightMap = new Dictionary<int, TrafficLight>();
        
        // key: waypoint uniqueId
        private Dictionary<int,TrafficWayPointData> TrafficWayPointMap = new Dictionary<int, TrafficWayPointData>();
        
        // key: waypoint uniqueId
        private Dictionary<int,TrafficLight> TrafficInnerPointMap = new Dictionary<int, TrafficLight>();

        public void Dispose()
        {
            foreach (var traffic in TrafficLightMap.Values)
            {
                if (traffic!=null)
                {
                    GameObject.Destroy(traffic);
                }
            }
            TrafficLightMap.Clear();
            TrafficWayPointMap.Clear();
            foreach (var traffic in TrafficInnerPointMap.Values)
            {
                if (traffic != null)
                {
                    GameObject.Destroy(traffic);
                }
            }
            TrafficInnerPointMap.Clear();
        }
        public void OnInit(GameObject pveTrafficLight)
        {
            pveTrafficLight.transform.parent = transform;

            TrafficLight[] lights = pveTrafficLight.GetComponentsInChildren<TrafficLight>();
            foreach (var trafficLight in lights)
            {
                TrafficLightMap.Add(trafficLight.trafficLightID,trafficLight);

                foreach (var pointMap in trafficLight.waitPointMaps)
                {
                    int wId = WayPointUtils.GetPointUniqueId(pointMap.WayPathID, pointMap.PointIndex);
                    TrafficWayPointData trafficWayPoint = new TrafficWayPointData();
                    trafficWayPoint.TrafficPointStatus = TrafficPointStatus.Walkable;
                    trafficWayPoint.WaitPointData = new List<TrafficWaitPointData>();
                    for (int i = 0; i < pointMap.NpcWaitPoints.Count; i++)
                    {
                        trafficWayPoint.WaitPointData.Add(new TrafficWaitPointData()
                        {
                            index = i,
                            status = true,
                            position = pointMap.NpcWaitPoints[i].transform.position,
                            forward = pointMap.NpcWaitPoints[i].transform.forward,
                        });
                    }
                    
                    TrafficWayPointMap.Add(wId,trafficWayPoint);
                }

                foreach (var pointMap in trafficLight.innerPointMaps)
                {
                    int uniqueID = WayPointUtils.GetPointUniqueId(pointMap.WayPathID, pointMap.PointIndex);
                    TrafficInnerPointMap.Add(uniqueID,trafficLight);
                }
                
            }

            foreach (var trafficLight in lights)
            {
                trafficLight.OnInit(this);
            }
        }


        public void OnTrafficRed(int lightId)
        {
            TrafficLight trafficLight = TrafficLightMap[lightId];
            foreach (var pointMap in trafficLight.waitPointMaps)
            {
                int wId = WayPointUtils.GetPointUniqueId(pointMap.WayPathID, pointMap.PointIndex);
                TrafficWayPointMap[wId].TrafficPointStatus = TrafficPointStatus.NotWalkable;
            }
        }

        public void OnTrafficGreen(int lightId)
        {
            TrafficLight trafficLight = TrafficLightMap[lightId];
            foreach (var pointMap in trafficLight.waitPointMaps)
            {
                int wId = WayPointUtils.GetPointUniqueId(pointMap.WayPathID, pointMap.PointIndex);
                TrafficWayPointMap[wId].TrafficPointStatus = TrafficPointStatus.Walkable;
                foreach (var waitPointData in TrafficWayPointMap[wId].WaitPointData)
                {
                    waitPointData.status = true;
                    waitPointData.npcId = -1;
                }

                TrafficWayPointMap[wId].CurrentWaitCount = 0;
            }
        }


        // 获取路点的可行走状态
        public TrafficPointStatus GetPointStatus(int wayId,int pointIndex)
        {
            int wId = WayPointUtils.GetPointUniqueId(wayId, pointIndex);

            return GetPointStatus(wId);
        }

        public TrafficPointStatus GetPointStatus(int uniqueId)
        {
            if (TrafficWayPointMap.TryGetValue(uniqueId,out var pointData))
            {
                return pointData.TrafficPointStatus;
            }

            return TrafficPointStatus.Walkable;
        }
        
        /// <summary>
        /// 获取可等待点位
        /// </summary>
        /// <param name="wayId"></param>
        /// <param name="pointIndex"></param>
        /// <param name="isMain"> 是否为主角 </param>
        /// <returns></returns>
        public TrafficWaitPointData GetNpcWaitPoint(int wayId, int pointIndex,int npcId)
        {
            int wId = WayPointUtils.GetPointUniqueId(wayId, pointIndex);

            if (TrafficWayPointMap.TryGetValue(wId,out var pointData))
            {
                if (pointData.CurrentWaitCount == NFConstValue.MAX_TRAFFIC_WAIT_COUNT - 1 && !NFMgr.DataManager.IsMainCharactor(npcId))
                {
                    bool containsMain = false;
                    foreach (var waitPointData in pointData.WaitPointData)
                    {
                        if (!waitPointData.status && NFMgr.DataManager.IsMainCharactor(waitPointData.npcId))
                        {
                            containsMain = true;
                            break;
                        }
                    }

                    if (!containsMain)
                    {
                        return null;
                    }
                }
                TrafficWaitPointData vaildWaitData = null;

                if (pointData.CurrentWaitCount > 1)
                {
                    // 找最近的点
                    NpcData npcData = NFMgr.DataManager.GetNpcData(npcId);

                    float minDistance = 100000f;
                    for (int i = 0; i < pointData.WaitPointData.Count; i++)
                    {
                        var waitData = pointData.WaitPointData[i];
                        if (waitData.status)
                        {
                            float dis = Vector3.Distance(waitData.position, npcData.Position);
                            if (dis < minDistance)
                            {
                                minDistance = dis;
                                vaildWaitData = waitData;
                            }
                        }

                    }
                }
                else
                {
                    // 没有人时默认找第一个点
                    vaildWaitData = pointData.WaitPointData[pointData.CurrentWaitCount];
                }

                if (vaildWaitData!=null)
                {
                    vaildWaitData.status = false;
                    vaildWaitData.npcId = npcId;
                    pointData.CurrentWaitCount++;
                    return vaildWaitData;
                }
            }
            
            // 没有等待点位了
            return null;
        }


        public TrafficWaitPointData GetWaitPoint(int wayId, int pointIndex, int waitIndex)
        {
            int wId = WayPointUtils.GetPointUniqueId(wayId, pointIndex);

            if (TrafficWayPointMap.TryGetValue(wId, out var pointData))
            {
                return pointData.WaitPointData[waitIndex];
            }

            return null;
        }


        public TrafficLight InnerWayPointLight(int wayId, int pointIndex)
        {
            int wId = WayPointUtils.GetPointUniqueId(wayId, pointIndex);
            TrafficLight trafficLight;
            if (TrafficInnerPointMap.TryGetValue(wId,out trafficLight))
            {
                return trafficLight;
            }

            return null;
        }

        public bool IsTrafficLightPoint(int wayId, int pointIndex)
        {
            int wId = WayPointUtils.GetPointUniqueId(wayId, pointIndex);
            return TrafficWayPointMap.ContainsKey(wayId) || TrafficInnerPointMap.ContainsKey(wayId);
        }

    }
}
